#include "global.h"

/**
 * @brief  ADC初始化函数
 * @note   配置ADC1四通道扫描转换，并通过DMA循环存储数据到全局数组adcValue[4]中。
 * @特性：
 *         - 使用PA0-PA3四个引脚（对应ADC通道0-3）
 *         - ADC时钟配置为6MHz，采样时间为55.5个周期
 *         - 启用连续扫描模式，自动循环转换
 *         - 使用DMA将转换结果存储到adcValue数组中
 * @警告  ADC_NbrOfChannel必须与实际配置的通道数一致
 */
void adc_init(void)
{
    /* 外设时钟使能 */
    RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1EN, ENABLE);     // 使能DMA1时钟（用于ADC数据传输）
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  // 使能ADC1时钟（APB2总线）
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟（PA0-PA3）

    /* ADC时钟配置 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 36MHz/6=6MHz（须确保不超过ADC最大工作频率）

    /* GPIO初始化（模拟输入模式） */
    GPIO_InitTypeDef GPIO_InitStructure = {
        .GPIO_Mode = GPIO_Mode_AIN,    // 模拟输入模式（ADC专用）
        .GPIO_Speed = GPIO_Speed_50MHz // IO速度不影响模拟功能，保持默认
    };
    // 初始化四个ADC通道对应的GPIO引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // PA0 -> ADC_Channel_0
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // PA1 -> ADC_Channel_1
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // PA2 -> ADC_Channel_2
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // PA3 -> ADC_Channel_3
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* ADC通道序列配置 */
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 转换序列1：PA0
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); // 转换序列2：PA1
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); // 转换序列3：PA2
    ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5); // 转换序列4：PA3

    /* ADC工作模式配置 */
    ADC_InitTypeDef ADC_InitStructure = {
        .ADC_Mode = ADC_Mode_Independent,                  // 独立模式（无ADC交叉触发）
        .ADC_DataAlign = ADC_DataAlign_Right,              // 数据右对齐（标准配置）
        .ADC_ExternalTrigConv = ADC_ExternalTrigConv_None, // 软件触发（无需外部信号）
        .ADC_ContinuousConvMode = ENABLE,                  // 连续转换模式（重要！使能自动循环）
        .ADC_ScanConvMode = ENABLE,                        // 扫描模式（必须开启以实现多通道转换）
        .ADC_NbrOfChannel = ADC_CHANNEL_COUNT              // 通道数量（必须与实际配置数量一致）
    };
    ADC_Init(ADC1, &ADC_InitStructure);

    /* DMA传输配置（关键参数说明） */
    DMA_InitTypeDef DMA_InitStructure = {
        .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR,             // 外设地址：ADC数据寄存器（固定）
        .DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord, // 16位ADC数据
        .DMA_PeripheralInc = DMA_PeripheralInc_Disable,            // 外设地址固定（始终读取DR寄存器）
        .DMA_MemoryBaseAddr = (uint32_t)adcValue,                  // 内存目标地址：全局数组
        .DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord,         // 内存数据宽度16位
        .DMA_MemoryInc = DMA_MemoryInc_Enable,                     // 内存地址自增（按通道顺序存储）
        .DMA_BufferSize = ADC_CHANNEL_COUNT,                       // 传输数据量（4个通道）
        .DMA_Mode = DMA_Mode_Circular,                             // 循环模式（持续更新数据）
        .DMA_M2M = DMA_M2M_Disable,                                // 外设到内存模式
        .DMA_Priority = DMA_Priority_High                          // 高DMA优先级
    };
    DMA_Init(DMA1_Channel1, &DMA_InitStructure); // 使用DMA1通道1（ADC1固定映射）
    DMA_Cmd(DMA1_Channel1, ENABLE);              // 使能DMA通道

    /* 关联ADC与DMA */
    ADC_DMACmd(ADC1, ENABLE); // 使能ADC的DMA请求（转换完成触发传输）

    /* ADC启动流程 */
    ADC_Cmd(ADC1, ENABLE);      // 激活ADC1
    ADC_ResetCalibration(ADC1); // 复位校准寄存器（必须流程）
    while (ADC_GetResetCalibrationStatus(ADC1))
        ;                       // 等待复位完成（硬件自动清除标志）
    ADC_StartCalibration(ADC1); // 开始校准（上电后必须执行）
    while (ADC_GetCalibrationStatus(ADC1))
        ; // 等待校准完成（约需7个ADC时钟周期）

    /* 启动连续转换 */
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 触发首次转换（后续自动循环）
}
